/**************************************************************************** 
 * Meta，一个轻量级的静态分区Hypervisor 
 *
 * 版权(c) , 2022-
 *
 * 作者:
 *      Tupelo Shen <shenwanjiang2013@163.com>
 *
 * Meta是一个自由软件，你可以在遵循GNU GPLv2协议的条件下，重新修改并发布它。
 *
 ***************************************************************************/
#include <cpu.h>
#include <interrupts.h>
#include <platform.h>
#include <objcache.h>
#include <vm.h>
#include <fences.h>

/****************************************************************************
 ****                         变量声明                                   ****
 ****************************************************************************/
struct cpu_msg_node {
    node_t node;
    struct cpu_msg msg;
};

struct cpu           cpu __attribute__((section(".cpu_private")));
struct cpu_synctoken cpu_glb_sync = {.ready = false};
cpuid_t              CPU_MASTER __attribute__((section(".data")));

struct objcache      msg_cache;

/* 基于核间中断的消息处理函数 */
cpu_msg_handler_t   *ipi_cpumsg_handlers;
static size_t       ipi_cpumsg_handler_num;
extern uint8_t      _ipi_cpumsg_handlers_start;
extern uint8_t      _ipi_cpumsg_handlers_size;
extern uint8_t      _ipi_cpumsg_handlers_id_start;

/****************************************************************************
 ****                         私有函数接口                               ****
 ****************************************************************************/
static bool cpu_get_msg(struct cpu_msg *msg);

/****************************************************************************
 ****                         公共函数定义                               ****
 ****************************************************************************/
/**
 * 功能描述: 运行虚拟核
 * 入口参数: vcpu:      要运行的虚拟核
 * 出口参数: void
 * 返 回 值: void
 * 修改日期: 2022-09-21
 */
void cpu_init(cpuid_t cpu_id, paddr_t load_addr)
{
    cpu_arch_init(cpu_id, load_addr);

    cpu.id = cpu_id;
    list_init(&cpu.interface.event_list);

    if (cpu.id == CPU_MASTER) {
        cpu_sync_init(&cpu_glb_sync, platform.cpu_num);
        objcache_init(&msg_cache, sizeof(struct cpu_msg_node), SEC_HYP_GLOBAL,
                      false);

        ipi_cpumsg_handlers = (cpu_msg_handler_t*)&_ipi_cpumsg_handlers_start;
        ipi_cpumsg_handler_num =
            ((size_t)&_ipi_cpumsg_handlers_size) / sizeof(cpu_msg_handler_t);
        for (size_t i = 0; i < ipi_cpumsg_handler_num; i++) {
            ((size_t*)&_ipi_cpumsg_handlers_id_start)[i] = i;
        }
    }

    cpu_sync_barrier(&cpu_glb_sync);
}

/**
 * 功能描述: 核因为空闲而进入低功耗状态，然后唤醒时的执行流程
 * 入口参数: void
 * 出口参数: void
 * 返 回 值: void
 * 修改日期: 2022-09-21
 */
void cpu_idle_wakeup(void)
{
    /* 处理核间中断消息 */
    if (interrupts_check(IPI_CPU_MSG)) {
        interrupts_clear(IPI_CPU_MSG);
        cpu_msg_handler();
    }

    /**
     * 如果cpu此时被虚拟核占用，则执行VM代码;
     * 否则，再次进入空闲状态
     */
    if (cpu.vcpu != NULL) {
        vcpu_run(cpu.vcpu);
    } else {
        cpu_idle();
    }
}

/**
 * 功能描述: 根据msg调用对应的消息处理函数
 * 入口参数: msg:      要获取的消息
 * 出口参数: void
 * 返 回 值: bool:     成功返回true；否则false          
 * 修改日期: 2022-09-21
 */
void cpu_msg_handler()
{
    struct cpu_msg msg;
    while (cpu_get_msg(&msg)) {
        if (msg.handler < ipi_cpumsg_handler_num &&
            ipi_cpumsg_handlers[msg.handler]) {
            ipi_cpumsg_handlers[msg.handler](msg.event, msg.data);
        }
    }
}

/**
 * 功能描述: 发送核间中断消息
 * 入口参数: trgtcpu:   目标核
 *           msg,       消息结构体
 * 出口参数: void
 * 返 回 值: void
 * 修改日期: 2022-09-21
 */
void cpu_send_msg(cpuid_t trgtcpu, struct cpu_msg *msg)
{
    struct cpu_msg_node *node = objcache_alloc(&msg_cache);
    if (node == NULL) ERROR("cant allocate msg node");
    node->msg = *msg;
    list_push(&cpu_if(trgtcpu)->event_list, (node_t *)node);
    fence_sync_write();
    interrupts_cpu_sendipi(trgtcpu, IPI_CPU_MSG);
}

/**
 * 功能描述: cpu空闲状态的处理
 * 入口参数: void
 * 出口参数: void
 * 返 回 值: void
 * 修改日期: 2022-09-21
 */
void cpu_idle(void)
{
    cpu_arch_idle();

    /**
     * Should not return here.
     * cpu should "wake up" from idle in cpu_idle_wakeup
     * with a rewinded stack.
     */
    ERROR("Spurious idle wake up");
}

/****************************************************************************
 ****                         私有函数定义                               ****
 ****************************************************************************/
/**
 * 功能描述: 从objcache中获取核间消息的数据结构
 * 入口参数: msg:      要获取的消息
 * 出口参数: void
 * 返 回 值: bool:     成功返回true；否则false          
 * 修改日期: 2022-09-21
 */
static bool cpu_get_msg(struct cpu_msg *msg)
{
    struct cpu_msg_node *node = NULL;
    if ((node = (struct cpu_msg_node *)list_pop(&cpu.interface.event_list)) !=
        NULL) {
        *msg = node->msg;
        objcache_free(&msg_cache, node);
        return true;
    }
    return false;
}